import {EE, prompt} from "@/utils";
import React from "react";
import EnumOnFire from "@/pages/dv/constants/EnumOnFire";
import {merge, isFunction, round} from 'lodash';

interface IChart {
  [key: string]: DV.IChart
}

/**
 * dv本地缓存数据库
 */
export default class DvState {
  public scale: number;
  public maxZIndex: number;
  public selectedChartKey: string;
  public isEditingOfChartCode: boolean;
  public isEditingOfCss: boolean;
  public charts: IChart;
  public bgConfig: DV.IBgConfig;
  public cssConfig: DV.ICssConfig;
  public dvOption: any;
  public EnumChartFire: IEnumChartFireKey;

  constructor() {
    this.scale = 0.2;
    this.maxZIndex = 10;
    this.selectedChartKey = 'FIRST_COMPONENT3';
    this.isEditingOfChartCode = false; // 是否正在组件编程
    this.isEditingOfCss = false; // 是否正在修改css
    // ------配置-------
    this.charts = {}; // 每个组件都有唯一的标识uid
    this.bgConfig = {};
    this.dvOption = {
      height: 1,
      width: 1,
      name: '未命名'
    };
    this.cssConfig = {
      code: ''
    }
    // ------end--------

    // 组件编辑模式-订阅事件（动态生成，切换或销毁时自动取消订阅）
    this.EnumChartFire = {
      update_baseConfig: '',
      update_advanceConfig: '',
      update_dataConfig: '',
      update_codeConfig: '',
      update_functions: '',
    }
    // 初始化
    this.init();
  }

  init() {
    this.createChartFireKey(this.selectedChartKey);
  }

  /**
   * 更新组件
   * @param key
   * @param chartOption
   * @param isMerge 是否合并更新
   */
  updateChart(key: string, chartOption: DV.IChart, isMerge = false) {
    if (!key) return;
    try {
      if (isMerge) {
        this.charts[key] = Object.assign(this.charts[key], chartOption);
      } else {
        // 新增图表组件
        this.charts[key] = chartOption;
      }
      if (chartOption.zIndex || 0 > this.maxZIndex) {
        this.maxZIndex = chartOption.zIndex || 10;
      }
      EE.fire(EnumOnFire.updateChart, {[key]: this.charts[key]});
    } catch (e) {
    }

  }

  /**
   * 更新/添加组件
   * @param uid
   * @param chartOption
   * @param cb
   */
  addChart(uid: string, chartOption: DV.IChart, cb: () => void) {
    if (!uid) return;
    if (this.charts[uid]) {
      prompt.error('添加组件失败！UID重复');
      return;
    }
    // 新增图表组件
    this.charts[uid] = chartOption;
    if (chartOption.zIndex || 10 > this.maxZIndex) {
      this.maxZIndex = chartOption.zIndex || 10;
    }
    EE.fire(EnumOnFire.addChart, {[uid]: chartOption});
    EE.fire(EnumOnFire.updateChart, {[uid]: chartOption});

    if (isFunction(cb)) cb();
  }

  /**
   * 更新基础配置
   * @param key
   * @param config
   * @param isMerge
   */
  updateBaseConfig(key: string, config: IBaseConfig, isMerge: boolean = true) {
    if (!key) return;
    try {
      if (isMerge) {
        // 基础配置项可直接合并
        this.charts[key] = merge(this.charts[key], config);
      }
      EE.fire(EnumOnFire.updateChart, {[key]: this.charts[key]}, {[key]: config});

      EE.fire(EnumOnFire.update_baseConfig, {[key]: config});

      if (config.hasOwnProperty('width') || config.hasOwnProperty('height')) {
        EE.fire(EnumOnFire.update_size, {
          [key]: Object.assign({
            width: this.charts[key].width,
            height: this.charts[key].height,
          }, config)
        });
      }

      if (config.hasOwnProperty('left') || config.hasOwnProperty('top')) {
        const newPosition = Object.assign({}, {
          top: this.charts[key].top,
          left: this.charts[key].left,
        }, config)
        EE.fire(EnumOnFire.update_position, {[key]: newPosition}, newPosition);
      }

    } catch (e) {
    }
  }

  /**
   * 更新高级配置
   * @param uid
   * @param config
   * @param isMerge
   */
  updateAdvanceConfig(uid: string, config: DV.IAdvanceConfig, isMerge: boolean = true) {
    if (!uid) return;
    try {
      if (isMerge) {
        // 基础配置项可直接合并
        this.charts[uid] = merge(this.charts[uid], {config});
      } else {
        this.charts[uid].config = config;
      }
      // 不需要通知
      // EE.fire(EnumOnFire.updateChart, {[uid]: this.charts[uid]});
    } catch (e) {
    }
  }


  /**
   * 更新编程配置
   * @param key
   * @param codeConfig
   * @param isMerge
   */
  updateCodeConfig(key: string, codeConfig: DV.ICodeConfig, isMerge: boolean = true) {
    if (!key) return;
    try {
      if (isMerge) {
        // 基础配置项可直接合并
        this.charts[key] = Object.assign(this.charts[key], {codeConfig});
      } else {
        this.charts[key].codeConfig = codeConfig;
      }
      EE.fire(EnumOnFire.updateChart, {[key]: this.charts[key]});
    } catch (e) {
    }
  }

  /**
   * 更新数据配置
   * @param key
   * @param dataConfig
   * @param isMerge
   */
  updateDataConfig(key: string, dataConfig: DV.IDataConfig, isMerge: boolean = true) {
    if (!key) return;
    try {
      if (isMerge) {
        // 基础配置项可直接合并
        this.charts[key] = Object.assign(this.charts[key], {dataConfig});
      } else {
        this.charts[key].dataConfig = dataConfig;
      }
      // EE.fire(EnumOnFire.updateChart, {[key]: this.charts[key]});
    } catch (e) {
    }
  }

  /**
   * 更新事件配置
   * @param key
   * @param functions
   * @param isMerge
   */
  updateChartEvents(key: string, functions: DV.IChartEvent, isMerge: boolean = true) {
    if (!key) return;
    try {
      if (isMerge) {
        this.charts[key] = Object.assign(this.charts[key], {functions});
      } else {
        this.charts[key].events = functions;
      }
      EE.fire(EnumOnFire.updateChart, {[key]: this.charts[key]});
    } catch (e) {
    }
  }

  /**
   * 更新背景配置项
   */
  updateBgConfig(bgConfig: DV.IBgConfig) {
    this.bgConfig = merge(this.bgConfig, bgConfig);
    EE.fire(EnumOnFire.updateBgConfig, this.bgConfig);
  }

  /**
   * 更新主配置
   * @param dvOption
   */
  updateDvOption(dvOption: object) {
    this.dvOption = Object.assign(this.dvOption, dvOption);
    EE.fire(EnumOnFire.updateDvOption, this.dvOption);
  }

  /**
   * 更新主配置
   * @param cssConfig
   */
  updateCssConfig(cssConfig: DV.ICssConfig) {
    this.cssConfig = merge(this.cssConfig, cssConfig);
    // EE.fire(EnumOnFire.updateCssConfig, this.cssConfig);
  }

  /**
   * 面板缩放
   * @param scale
   */
  changeScale(scale: number) {
    scale = round(scale, 2);
    if (scale < 0.1) {
      scale = 0.1
    }
    if (scale > 2) {
      scale = 2
    }
    this.scale = scale;
    EE.fire(EnumOnFire.changeScale, scale);
  }

  /**
   * 当前选中的组件索引（切换组件时）
   * @param uid
   */
  selectedChart = (uid: string) => {
    // 如果正在组件编程，需要提示
    if (this.isEditingOfChartCode) {
      prompt.confirm(() => {
        this.selectedChartKey = uid;
        this.createChartFireKey(uid);
        EE.fire(EnumOnFire.selectedChartKey, uid, this.charts[uid]);
        this.isEditingOfChartCode = false;
      }, {
        title: '组件退出编辑状态警告',
        content: <span>
          组件<span style={{color: 'red'}}>[{this.charts[this.selectedChartKey].name}]</span>存在正在编辑的未保存代码，请注意保存！
          忽视将不保存代码。
        </span>,
        okText: '忽视',
        cancelText: '取消',
      })
    } else {
      this.selectedChartKey = uid;
      this.createChartFireKey(uid);
      EE.fire(EnumOnFire.selectedChartKey, uid, this.charts[uid]);
    }
  }


  createFireKey(key: string, uid: string, action: string = 'update') {
    return [action, key, uid].join('_')
  }

  /**
   * 创建组件编辑订阅事件
   * @param uid
   */
  createChartFireKey(uid = this.selectedChartKey) {
    this.offChartFireKey(); // 及时取消订阅，性能优化
    this.EnumChartFire = {
      update_baseConfig: this.createFireKey('baseConfig', uid),
      update_advanceConfig: this.createFireKey('advanceConfig', uid),
      update_dataConfig: this.createFireKey('dataConfig', uid),
      update_codeConfig: this.createFireKey('codeConfig', uid),
      update_functions: this.createFireKey('functions', uid),
    }
  }

  /**
   * 取消单一组件订阅
   */
  offChartFireKey() {
    if (!this.EnumChartFire.update_baseConfig.includes(this.selectedChartKey)) {
      Object.keys(this.EnumChartFire).forEach(key => {
        EE.off(key);
      })
    }

  }

  /**
   * 取消选中
   */
  cancelSelected() {
    this.selectedChart('');
  }
}
